package com.za.plugin.util;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.za.plugin.pojo.Content;
import com.za.plugin.pojo.PredixStrAndCount;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.statement.select.SelectItem;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.mapping.ParameterMapping;

import java.util.*;
import java.util.stream.Collectors;

public class SqlUtil {

    private SqlUtil() {
    }

    public static final HashSet<String> KEY_WORD_SET = new HashSet<>(Arrays.asList("desc", "group", "identity"));

    public static boolean isParamMap(Object paramObj) {
        return paramObj instanceof MapperMethod.ParamMap;
    }

    public static List<String> ExprToString(List<SQLExpr> columns) {
        if (CollUtil.isEmpty(columns)) {
            return Collections.emptyList();
        }
        return columns.stream().map(SQLUtils::toMySqlString).collect(Collectors.toList());
    }

    public static List<Integer> findAutoIncrIdx(List<String> columnList, List<String> autoIncrProperties) {
        ArrayList<Integer> res = new ArrayList<>();
        if (CollUtil.isEmpty(autoIncrProperties)) {
            return res;
        }
        for (int i = 0; i < columnList.size(); i++) {
            if (autoIncrProperties.contains(columnList.get(i))) {
                res.add(i);
            }
        }
        return res;
    }

    /**
     * 不获取 select 开头的表名
     *
     * @param sql
     * @return
     */
    public static String getTableNameFromSql(String sql) {
        String tableName = "";
        // insert, update 这些 sql 怎么获取表名,不同的类型的 sql 获取表名的方式不一样
        if (sql.startsWith("update ")) {
            tableName = sql.split("\\s+")[1].toUpperCase();
        } else if (sql.startsWith("replace into ") || sql.startsWith("insert into ")) {
            tableName = sql.split("\\s+")[2].toUpperCase();
        } else if (sql.startsWith("insert ignore into")) {
            // 根据 insert ignore into 的特点获取表名称
            int left = sql.indexOf("(");
            int into = sql.indexOf("into");
            tableName = sql.substring(into + 4, left).toUpperCase().trim();
            if (tableName.contains(".")) {
                tableName = tableName.split("\\.")[1];
            }
        }
        // 处理 tblName(a,b,c) 这种情况
        if (tableName.contains("(")) {
            tableName = tableName.substring(0, tableName.indexOf("("));
        }
        return tableName.trim();

    }

    public static boolean isSelect(String sql) {
        return sql.toLowerCase().trim().startsWith("select ");
    }


    // 获取 select ... from 之前的查询字段，兼容各种情况
    public static Map<String, String> getSelectProperties(String sql, int begin) {
        Map<String, String> map = new LinkedHashMap<>();
        int left = sql.indexOf("select ", begin) + "select ".length();

        int right = sql.indexOf(" from ", left);
        int rightUnion = sql.indexOf(" union ", left);
        if (rightUnion >= 0 && rightUnion < right) {
            right = rightUnion;
        }
        // checkRightIdx() 防止 select 中又嵌套一个 select 子查询
        while (!StrUtil.checkRightIdx(sql, left, right)) {
            right = sql.indexOf(" from ", right + 5);
        }
        if (right == -1) {
            return map;
        }
        // select * from xxx
        String selectSection = sql.substring(left, right).trim();
        if ("*".equals(selectSection)) {
            map.put("*", "*");
            return map;
        }
        // 不支持 DM 语法解析
        if (!sql.trim().startsWith("MERGE INTO ")) {
            MySqlStatementParser parser = new MySqlStatementParser(("select " + selectSection).toLowerCase());
            SQLSelectStatement sqlSelectStatement = (SQLSelectStatement) parser.parseStatement();
            if (SQLUtils.toMySqlString(sqlSelectStatement).contains(" DISTINCT ")) {
                processSelectItemWithDistinct(sql, left, right, map);
            } else {
                List<SQLSelectItem> selectList = ((MySqlSelectQueryBlock) sqlSelectStatement.getSelect().getQuery()).getSelectList();
                processSelectItem(map, selectList);
            }

            return map;
        }

        /*// 不会执行以下代码
        List<String> list = StrUtil.getSegment(sql, left, right);
        //这是对 select 的各个部分做成一个 map,别名->值，可能有别名，也可能没有，可能使用 as 做别名间隔符，也可能是空格
        for (String s : list) {
            if (!s.contains("distinct") && !s.contains("round") && !s.contains("select")) {
                SelectItem selectItem = null;
                try {
                    selectItem = ((PlainSelect) ((Select) CCJSqlParserUtil.parse("select " + s)).getSelectBody()).getSelectItems().get(0);
                } catch (JSQLParserException e) {
                    System.out.println("报错的 SQL ：" + "select " + s);
                    throw new RuntimeException(e);
                }
                if (selectItem instanceof SelectExpressionItem) {
                    Alias alias = ((SelectExpressionItem) selectItem).getAlias();
                    String expr = ((SelectExpressionItem) selectItem).getExpression().toString().trim();
                    if (alias != null) {
                        map.put(alias.getName().trim(), expr);
                    } else {
                        map.put(expr, expr);
                    }
                    continue;
                }
            }
            s = s.trim().replaceAll("\\s*\\(", "\\(").replaceAll("\\s*\\)", "\\)").replaceAll("\\s*\\.\\s*", ".").replaceAll("\\s*\\,\\s*", "\\,");
            s = s.replace(")as", ") as");
            if (s.contains(" as ")) {
                int idx = s.indexOf(" as ");
                // 避免出现 CONCAT(c.agri_res_name,': ',(SELECT 0 + CAST(c.total_dosage_value AS CHAR)), ' ',c.unit_name) as agriResUseDesc
                while (idx != -1 && !checkASValid(idx, s)) {
                    idx = s.indexOf(" as ", idx + 4);
                }
                if (idx != -1) {
                    map.put(s.substring(idx + 4).trim(), s.substring(0, idx).trim());
                } else {
                    int spaceIdx = s.lastIndexOf(" ");
                    if (spaceIdx >= 0) {
                        map.put(s.substring(spaceIdx + 1).trim(), s.substring(0, spaceIdx).trim());
                    } else {
                        map.put(s, s);
                    }
                }
            } else if (s.contains(" ")) {
                // case when a != null then ifnull(a,0) else b end
                if (s.endsWith(" end")) {
                    map.put(s, s);
                    continue;
                } else if (s.contains(" end ")) { // 可能不止一个 end，已经遇到过
                    if (s.contains(")")) {
                        String key = s.substring(s.lastIndexOf(")") + 1).trim();
                        key = key.contains("as ") ? key.split("\\s+")[1] : key;
                        map.put(key, s.substring(0, s.lastIndexOf(")") + 1));
                        continue;
                    } else {
                        int idx = s.lastIndexOf(" end ");
                        map.put(s.substring(idx + 5).trim(), s.substring(0, idx).trim() + " end");
                        continue;
                    }
                }
                if (s.contains("(")) {
                    int leftIdx = s.indexOf("(");
                    Content expectContent = StrUtil.getExpectContent(s, leftIdx);
                    assert expectContent != null;

                    int end = expectContent.getEnd();
                    if (s.length() > end && s.substring(end).trim().length() > 0) {
                        map.put(s.substring(end).trim(), s.substring(0, end).trim());
                    } else {
                        map.put(s, s);
                    }
                    continue;
                }

                // select distinct c.id
                int idx = s.lastIndexOf(" ");
                String[] split = s.split("\\s+");
                if (split.length == 2 && split[0].equalsIgnoreCase("distinct")) {
                    map.put(s, s);
                    continue;
                }
                map.put(s.substring(idx + 1).trim(), s.substring(0, idx).trim());
            } else if (s.contains("(")) {
                int leftIdx = s.indexOf("(");
                Content expectContent = StrUtil.getExpectContent(s, leftIdx);
                assert expectContent != null;
                int end = expectContent.getEnd();
                if (s.length() > end && s.substring(end).trim().length() > 0) {
                    map.put(s.substring(end).trim(), s.substring(0, end).trim());
                } else {
                    map.put(s, s);
                }
            } else {
                s = s.replace("'", "");
                map.put(s, s);
            }
        }*/
        // 不会执行以下代码
        processSelectItemWithDistinct(sql, left, right, map);
        return map;
    }

    private static void processSelectItem(Map<String, String> map, List<SQLSelectItem> selectList) {
        selectList.forEach(select -> {
            String alias = select.getAlias();
            String propVal = "";
            SQLExpr sqlExpr = select.getExpr();
            propVal = SQLUtils.toMySqlString(sqlExpr);
            if (alias != null) {
                map.put(alias, propVal);
            } else {
                map.put(propVal, propVal);
            }
        });
    }


    /**
     * 双指针左右扩展获取一个合法的 Select 子句
     *
     * @param sql
     * @param centerIdx
     * @return
     */
    public static String getValidSelect(String sql, int centerIdx) {
        int leftFlag = 0, i = centerIdx, j = centerIdx, len = sql.length();
        while (i >= 0) {
            char ch = sql.charAt(i);
            if (ch == '(') {
                leftFlag++;
            } else if (ch == ')') {
                leftFlag--;
            }
            if (leftFlag == 1) {
                break;
            }
            i--;
        }
        leftFlag = 0;
        while (j < len) {
            char ch = sql.charAt(j);
            if (ch == '(') {
                leftFlag++;
            } else if (ch == ')') {
                leftFlag--;
            }
            if (leftFlag == -1) {
                break;
            }
            j++;
        }
        return sql.substring(i + 1, j);
    }


    /**
     * 正常情况下会返回 sql.length()
     *
     * @param sql
     * @param left
     * @return
     */
    public static int getSqlEnd(String sql, int left) {
        int j = left;
        int leftFlag = 0;
        while (j < sql.length()) {
            if (sql.charAt(j) == '(') {
                leftFlag++;
            } else if (sql.charAt(j) == ')') {
                leftFlag--;
            }
            // select xxx , (select 1) as col ,  from xxx 这种情况，此时 sql.charAt(j)一定是“)”
            if (leftFlag == -1) {
                break;
            }
            j++;
        }
        return j;
    }


    private static boolean checkASValid(int idx, String s) {
        return s.indexOf(')', idx) == -1;
    }

    // "produce.tbl" 有"."且有双引号的要去掉双引号
    public static String getTableName(String tableName) {
        return tableName.replaceAll("\"", "").replaceAll("'", "");
    }


    // 兼容 update table set id=?,name=? where id=23 这种情况
    public static List<String> getKeyName2(String sql) {
        int left = sql.indexOf('(');
        int right = sql.indexOf(')', left);
        if ((left == -1) || (right == -1) || (right == left + 1)) {
            return getKeyNameOnUpdate(sql);
        }
        return Arrays.stream(sql.substring(left + 1, right).split(",")).map(String::trim).collect(Collectors.toList());
    }

    public static List<String> getKeyNameOnUpdate(String sql) {
        int left = sql.indexOf("set");
        int right = sql.indexOf("where", left);
        // 可能没有 where 部分
        if (right == -1) {
            right = sql.length();
        }
        return StrUtil.getSegment(sql, left + "set".length(), right).stream().map(it -> it.replaceAll("\\s+", " ")).filter(it -> it.length() > 0).map(it -> it.split("=")[0].trim()).collect(Collectors.toList());
    }

    public static Map<String, String> getFunctionValueBatch(String sql, List<String> autoIncrProperties) {
        List<String> keyName2;
        Map<String, String> map = new LinkedHashMap<>();
        if (sql.startsWith("update")) {
            // update tbl_agri_res where id = ?
            int left = sql.indexOf("set");
            if (left == -1) {
                return map;
            }
            int right = sql.indexOf("where", left);
            if (right == -1) {
                right = sql.length();
            }
            List<String> splitArr = StrUtil.getSegment(sql, left + "set".length(), right).stream().map(it -> it.replaceAll("\\s+", " ")).filter(it -> it.length() > 0).collect(Collectors.toList());
            for (String segment : splitArr) {
                int idx = segment.indexOf("=");
                String key = segment.substring(0, idx);
                String value = segment.substring(idx + 1);
                String[] kvs = new String[]{key, value};
//                !"?".equals(kvs[1]) 存在 id=id+? 这种情况
                // 存在 sell_group_id =case when id=? then ? when id=? then ? end 这种情况
                // 存在 set  mission_rate=(case when total_overdue_count!=0 and total_mission_count!=0 then 100*(1-(total_overdue_count/total_mission_count)) when total_overdue_count =0 and total_mission_count!=0 then 100 else null end )
                if (!value.contains("?")) {
                    map.put(kvs[0].trim(), kvs[1].trim());
                }
            }
            return map;
        } else {
            keyName2 = getKeyName2(sql);
        }
        int first = sql.indexOf('(');
        int second = sql.indexOf('(', first + 1);
        if (first == -1 || second == -1) {
            return map;
        }
        Content contentObj = StrUtil.getExpectContent(sql, second);
        List<String> valList = StrUtil.getSegment(sql, second + 1, contentObj.getEnd() - 1);
        int skipCnt = 0;
        for (int i = 0; i < keyName2.size(); i++) {
            String key = keyName2.get(i).trim();
            if (autoIncrProperties.contains(key)) {
                skipCnt++;
                continue;
            }
            // 有一种特殊情况，id 是自增列被跳过了，即 keyName2 和 valList 的 size 不相等，就会越界，但 mybatis 是支持的
            // if 打补丁
            int j = i;
            if (keyName2.size() > valList.size()) {
                j -= skipCnt;
            }
            // cast(? as varchar)
            if (!valList.get(j).trim().contains("?")) {
                map.put(key, valList.get(j).trim());
            }
        }
        return map;
    }

    public static String strFromDualForEach(List<String> keys, Map<String, ParameterMapping> map,
                                            List<ParameterMapping> parameterMappings, String sql,
                                            List<String> autoIncrProperties,
                                            List<ParameterMapping> parameterMappingsCopy,
                                            Set<String> pKs) {
        StringBuilder sb = new StringBuilder(" select ");

        List<String> javaKeys = StrUtil.getKeyName(keys);
        List<String> sqlKeys = getKeyName2(sql);
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        HashMap<String, String> sql2JavaMap = new HashMap<>();
        getSql2JavaMap(statement, sqlKeys, sql2JavaMap, javaKeys);
        Map<String, String> functionValMap = getFunctionValueBatch(sql, autoIncrProperties);

        PredixStrAndCount predixStrAndCount = StrUtil.getPredixStrAndCount(keys);
        int count = predixStrAndCount.getCount();
        String iteratorPrefix = predixStrAndCount.getIteratorPrefix();

        // 下面这段代码很可能会用在下面TODO那里，不能删
        Map<String, ParameterMapping> sqlMap = new LinkedHashMap<>();
        int idx = sql.indexOf("(");
        Content expectContent = StrUtil.getExpectContent(sql, idx);
        String expectStr = expectContent.getExpectStr();
        List<String> propertyArr = Arrays.stream(expectStr.split(",")).map(String::trim).collect(Collectors.toList());
        int len = (int) Math.ceil(((double) parameterMappingsCopy.size()) / propertyArr.size());
        int j = 0;
        for (int i = 0; i < len; i++) {
            for (String property : propertyArr) {
                // 有主键就必须包含主键，但不能包含自增列
                if (!pKs.contains(property) && (autoIncrProperties.contains(property) || functionValMap.containsKey(property))) {
                    continue;
                }
                sqlMap.put(iteratorPrefix + i + "." + property.trim(), parameterMappingsCopy.get(j++));
            }
        }

        j = 0;
        for (int i = 0; i < count; i++) {
            for (String key : sqlKeys) {
                if (!pKs.contains(key) && autoIncrProperties.contains(key)) {
                    j++;
                    continue;
                }
                if (functionValMap.containsKey(key)) {
                    if (i==0){
                        sb.append(functionValMap.get(key)).append(" ").append(StrUtil.toJavaProperty(key)).append(",");
                    }else{
                        sb.append(functionValMap.get(key)).append(",");
                    }

                } else {
                    // 批量插入时，参数既可以有 List<JavaBean> , 也可以有 String 参数
                    if (map.containsKey(iteratorPrefix + i + "." + sql2JavaMap.get(key))) {
                        parameterMappings.add(map.get(iteratorPrefix + i + "." + sql2JavaMap.get(key)));
                    } else if (map.containsKey(sql2JavaMap.get(key))) {
                        parameterMappings.add(map.get(sql2JavaMap.get(key)));
                    } else {
                        // TODO
                        System.out.println(sql2JavaMap.get(key) + "可能没有处理");
                    }
                    if (i==0){
                        sb.append(" ? ").append(sql2JavaMap.get(key)).append(",");
                    }else{
                        sb.append("?,");
                    }

                    j++;
                }
            }
            if (i < count - 1) {
                sb.deleteCharAt(sb.length() - 1);
                sb.append(" from dual UNION ALL select ");
            }
        }
        return sb.deleteCharAt(sb.length() - 1).append(" from dual ").toString();
    }

    private static void getSql2JavaMap(SQLStatement statement, List<String> sqlKeys, HashMap<String, String> sql2JavaMap, List<String> javaKeys) {
        if (statement instanceof MySqlInsertStatement) {
            MySqlInsertStatement stat = (MySqlInsertStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int j = 0;
                for (int i = 0; i < sqlKeys.size(); i++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(i)))) {
                        sql2JavaMap.put(sqlKeys.get(i), javaKeys.get(j));
                        j++;
                    }
                }
            }
        } else if (statement instanceof MySqlReplaceStatement) {
            MySqlReplaceStatement stat = (MySqlReplaceStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int j = 0;
                for (int i = 0; i < sqlKeys.size(); i++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(i)))) {
                        sql2JavaMap.put(sqlKeys.get(i), javaKeys.get(j));
                        j++;
                    }
                }
            }
        }
    }

    // replace into 和 on duplicate key update 当参数列表里有 id 或 唯一键时才开始比较是否要更新，
    // 否则就插入
    public static String onStr(Set<String> pks, List<String> keys, boolean isForeach, List<String> autoIncrProperties,
                               Map<String, List<String>> pkAndUniqueKeys, String sql) {
        StringBuilder sb = new StringBuilder();
        List<String> javaKeys = StrUtil.getKeyName(keys);
        List<String> sqlKeys = getKeyName2(sql);
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        HashMap<String, String> sql2JavaMap = new HashMap<>();
        if (statement instanceof MySqlInsertStatement) {
            MySqlInsertStatement stat = (MySqlInsertStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int j = 0;
                for (int i = 0; i < sqlKeys.size(); i++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(i)))) {
                        sql2JavaMap.put(sqlKeys.get(i), javaKeys.get(j));
                        j++;
                    }
                }
            }
        } else if (statement instanceof MySqlReplaceStatement) {
            MySqlReplaceStatement stat = (MySqlReplaceStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int j = 0;
                for (int i = 0; i < sqlKeys.size(); i++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(i)))) {
                        sql2JavaMap.put(sqlKeys.get(i).toLowerCase().trim(), javaKeys.get(j).trim());
                        j++;
                    }
                }
            }
        }
        if (isForeach) {
            keys = StrUtil.getKeyName(keys);
        }
        for (String pk : pks) {
            if (!sqlKeys.contains(pk) /*|| autoIncrProperties.contains(pk)*/) {
                continue;
            }
            if (pk.contains(".")) {
                pk = pk.split("\\.")[1];
            }
            sb.append("t.").append(sql2JavaMap.get(pk)).append("=o.").append(pk).append(" and ");
        }
        sb = deleteAnd(sb);

        if (sb.toString().isEmpty() && CollUtil.isNotEmpty(pkAndUniqueKeys)) {
            HashSet<String> javaKeySet = new HashSet<>(javaKeys);
            boolean containsUnique = false;
            for (Map.Entry<String, List<String>> entry : pkAndUniqueKeys.entrySet()) {
                List<String> value = entry.getValue().stream().map(String::toLowerCase)
                        .map(String::trim).collect(Collectors.toList());
                if (javaKeySetIsContains(javaKeySet, value, sql2JavaMap)) {
                    for (String val : value) {
                        sb.append("t.").append(sql2JavaMap.get(val)).append("=o.").append(val).append(" and ");
                    }
                    containsUnique = true;
                    break;
                }
                sb = deleteAnd(sb);
            }
            if (!containsUnique) {
                // 当 replace into 永为 false，直接使用 insert 就可以了，此时参数列表里没有 id 和 唯一键 。
                sb.append(" false ");
            }
        }
        sb = deleteAnd(sb);
        if (cn.hutool.core.util.StrUtil.isBlank(sb.toString())) {
            sb.append(" false ");
        }
        return sb.toString();
    }

    private static boolean javaKeySetIsContains(HashSet<String> javaKeySet, List<String> uniqueKeys, HashMap<String, String> sql2JavaMap) {
        if (CollUtil.isEmpty(uniqueKeys)) {
            return false;
        }
        for (String uniqueKey : uniqueKeys) {
            if (!javaKeySet.contains(sql2JavaMap.get(uniqueKey))) {
                return false;
            }
        }
        return true;

    }

    private static StringBuilder deleteAnd(StringBuilder sb) {
        if (sb.toString().endsWith(" and ")) {
            sb = sb.delete(sb.lastIndexOf(" and "), sb.length());
        }
        return sb;
    }

    public static String setStrForEach(List<String> keys, Set<String> pks,
                                       List<String> autoIncrProperties,
                                       String sql,
                                       Map<String, List<String>> pkAndUniqueKeys) {
        Set<String> pkAndUniqueKeySet = getPkAndUniqueKeyList(pkAndUniqueKeys);
        StringBuilder sb = new StringBuilder();
        List<String> javaKeys = StrUtil.getKeyName(keys);
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        HashMap<String, String> java2SqlMap = new HashMap<>();
        if (statement instanceof MySqlInsertStatement) {
            MySqlInsertStatement stat = (MySqlInsertStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int i = 0;
                for (int j = 0; j < values.size(); j++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(j)))) {
                        java2SqlMap.put(javaKeys.get(i), SQLUtils.toSQLString(columns.get(j)));
                        i++;
                    }

                }
            }
        } else if (statement instanceof MySqlReplaceStatement) {
            MySqlReplaceStatement stat = (MySqlReplaceStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int i = 0;
                for (int j = 0; j < values.size(); j++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(j)))) {
                        java2SqlMap.put(javaKeys.get(i), SQLUtils.toSQLString(columns.get(j)));
                        i++;
                    }
                }
            }
        }
        for (String key : javaKeys) {
            if (pks.contains(java2SqlMap.get(key))
                    || autoIncrProperties.contains(java2SqlMap.get(key))
                    || pkAndUniqueKeySet.contains(java2SqlMap.get(key))) {
                continue;
            }
            sb.append("o.").append(java2SqlMap.get(key)).append("=").append("t.").append(key).append(",");
        }
        return sb.deleteCharAt(sb.length() - 1).toString();

    }

    private static Set<String> getPkAndUniqueKeyList(Map<String, List<String>> pkAndUniqueKeys) {
        HashSet<String> set = new HashSet<>();
        if (CollUtil.isEmpty(pkAndUniqueKeys)) {
            return set;
        }
        for (Map.Entry<String, List<String>> entry : pkAndUniqueKeys.entrySet()) {
            List<String> values = entry.getValue().stream().map(String::trim)
                    .map(String::toLowerCase).collect(Collectors.toList());
            set.addAll(values);
        }
        return set;
    }

    public static String strFromDualSimple(List<String> keys, Map<String, ParameterMapping> map, List<ParameterMapping> parameterMappings, String sql, Set<String> pks, List<String> autoIncrProperties) {
        StringBuilder ret = new StringBuilder(" select ");
        keys = getKeyName2(sql);
        Map<String, String> functionValMap = getFunctionValueBatch(sql, autoIncrProperties);
        for (String key : keys) {
            if (functionValMap.containsKey(key)) {
                ret.append(functionValMap.get(key)).append(" ").append(StrUtil.toJavaProperty(key)).append(",");
            } else {
                if (map.containsKey(StrUtil.toJavaProperty(key))) {
                    parameterMappings.add(map.get(StrUtil.toJavaProperty(key)));
                } else {
                    System.err.println(StrUtil.toJavaProperty(key) + "属性在strFromDualSimple没添加到parameterMappings列表");
                }
                ret.append(" ? ").append(StrUtil.toJavaProperty(key)).append(" ,");
            }
        }
        return ret.deleteCharAt(ret.length() - 1).append(" from dual").toString();
    }

    public static String setStrSimple(List<String> keys, Map<String, ParameterMapping> map,
                                      List<ParameterMapping> parameterMappings,
                                      Set<String> pks, String sql,
                                      List<String> autoIncrProperties,
                                      Map<String, List<String>> pkAndUniqueKeys) {
        StringBuilder sb = new StringBuilder();
        Set<String> pkAndUniqueKeySet = getPkAndUniqueKeyList(pkAndUniqueKeys);
        keys = getKeyName2(sql);
        Map<String, String> functionValMap = getFunctionValueBatch(sql, autoIncrProperties);
        for (String key : keys) {
            // set 的时候跳过主键和自增列
            if (pks.contains(key) || autoIncrProperties.contains(key)||
                    pkAndUniqueKeySet.contains(key)) {
                continue;
            }
            sb.append("o.").append(StrUtil.toSqlProperty(key)).append("=");
            if (functionValMap.containsKey(key)) {
                sb.append(functionValMap.get(key)).append(",");
            } else {
                sb.append("?,");
                if (map.containsKey(StrUtil.toJavaProperty(key))) {
                    parameterMappings.add(map.get(StrUtil.toJavaProperty(key)));
                } else {
                    System.err.println(StrUtil.toJavaProperty(key) + "属性在setStrSimple没添加到parameterMappings列表");
                }
            }
        }
        return sb.deleteCharAt(sb.length() - 1).toString();
    }

    public static String insertStrSimple(List<String> keys, Map<String, ParameterMapping> map, List<ParameterMapping> parameterMappings, Set<String> pKs, String sql, List<String> autoIncrProperties) {
        StringBuilder sb = new StringBuilder("(");
        keys = getKeyName2(sql);
        Map<String, String> functionValMap = getFunctionValueBatch(sql, autoIncrProperties);
        for (String key : keys) {
            // 插入的时候跳过 自增列
            if (autoIncrProperties.contains(key)) {
                continue;
            }
            sb.append(StrUtil.toSqlProperty(key)).append(",");
        }
        sb.deleteCharAt(sb.length() - 1).append(")").append(" values (");
        for (String key : keys) {
            if (autoIncrProperties.contains(key)) {
                continue;
            }
            if (functionValMap.containsKey(key)) {
                sb.append(functionValMap.get(key)).append(",");
            } else {
                sb.append("?,");
                if (map.containsKey(StrUtil.toJavaProperty(key))) {
                    parameterMappings.add(map.get(StrUtil.toJavaProperty(key)));
                } else {
                    System.err.println(StrUtil.toJavaProperty(key) + "属性在insertStrSimple没添加到parameterMappings列表");
                }
            }
        }
        return sb.deleteCharAt(sb.length() - 1).append(")").toString();
    }

    public static String insertStrForEach(List<String> keys, Set<String> pks, String sql, List<String> autoIncrProperties) {
        StringBuilder sb = new StringBuilder("(");
        List<String> javaKeys = StrUtil.getKeyName(keys);
        keys = getKeyName2(sql);
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        HashMap<String, String> map = new HashMap<>();
        if (statement instanceof MySqlInsertStatement) {
            MySqlInsertStatement stat = (MySqlInsertStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int j = 0;
                for (int i = 0; i < keys.size(); i++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(i)))) {
                        map.put(keys.get(i), javaKeys.get(j));
                        j++;
                    }
                }
            }
        } else if (statement instanceof MySqlReplaceStatement) {
            MySqlReplaceStatement stat = (MySqlReplaceStatement) statement;
            List<SQLExpr> values = stat.getValuesList().get(0).getValues();
            List<SQLExpr> columns = stat.getColumns();
            if (values.size() == columns.size()) {
                int j = 0;
                for (int i = 0; i < keys.size(); i++) {
                    if ("?".equalsIgnoreCase(SQLUtils.toSQLString(values.get(i)))) {
                        map.put(keys.get(i), javaKeys.get(j));
                        j++;
                    }
                }
            }
        }
        Map<String, String> functionValMap = getFunctionValueBatch(sql, autoIncrProperties);
        for (String key : keys) {
            if (autoIncrProperties.contains(key)) {
                continue;
            }
            sb.append(" ").append(StrUtil.toSqlProperty(key)).append(",");
        }
        sb.deleteCharAt(sb.length() - 1).append(")").append(" values (");
        for (String key : keys) {
            if (autoIncrProperties.contains(key)) {
                continue;
            }
            if (functionValMap.containsKey(key)) {
                sb.append(functionValMap.get(key)).append(",");
                continue;
            }
            sb.append("t.").append(map.get(key)).append(",");
        }
        return sb.deleteCharAt(sb.length() - 1).append(")").toString();

    }

    public static boolean isForEach(List<ParameterMapping> parameterMappingsCopy) {
        boolean isForEach = false;
        for (ParameterMapping parameterMapping : parameterMappingsCopy) {
            if (parameterMapping.getProperty().contains("__frch_")) {
                isForEach = true;
            }
        }
        return isForEach;
    }

    public static Map<String, ParameterMapping> getPropertyMapFromParameterMappings(List<ParameterMapping> parameterMappingsCopy) {
        Map<String, ParameterMapping> map = new LinkedHashMap<>();
        for (ParameterMapping parameterMapping : parameterMappingsCopy) {
            map.putIfAbsent(parameterMapping.getProperty(), parameterMapping);
        }
        return map;
    }

    public static List<String> getKeysFromParameterMappingsCopy(List<ParameterMapping> parameterMappingsCopy) {
        return parameterMappingsCopy.stream().map(ParameterMapping::getProperty).distinct().collect(Collectors.toList());
    }

    private static void processSelectItemWithDistinct(String sql, int left, int right, Map<String, String> map) {
        List<String> list = StrUtil.getSegment(sql, left, right);
        //这是对 select 的各个部分做成一个 map,别名->值，可能有别名，也可能没有，可能使用 as 做别名间隔符，也可能是空格
        for (String s : list) {
            if (!s.contains("distinct") && !s.contains("round") && !s.contains("select")) {
                SelectItem selectItem = null;
                try {
                    selectItem = ((PlainSelect) ((Select) CCJSqlParserUtil.parse("select " + s)).getSelectBody()).getSelectItems().get(0);
                } catch (JSQLParserException e) {
                    System.out.println("报错的 SQL ：" + "select " + s);
                    throw new RuntimeException(e);
                }
                if (selectItem instanceof SelectExpressionItem) {
                    Alias alias = ((SelectExpressionItem) selectItem).getAlias();
                    String expr = ((SelectExpressionItem) selectItem).getExpression().toString().trim();
                    if (alias != null) {
                        map.put(alias.getName().trim(), expr);
                    } else {
                        map.put(expr, expr);
                    }
                    continue;
                }
            }
            s = s.trim().replaceAll("\\s*\\(", "\\(").replaceAll("\\s*\\)", "\\)").replaceAll("\\s*\\.\\s*", ".").replaceAll("\\s*\\,\\s*", "\\,");
            s = s.replace(")as", ") as");
            if (s.contains(" as ")) {
                int idx = s.indexOf(" as ");
                // 避免出现 CONCAT(c.agri_res_name,': ',(SELECT 0 + CAST(c.total_dosage_value AS CHAR)), ' ',c.unit_name) as agriResUseDesc
                while (idx != -1 && !checkASValid(idx, s)) {
                    idx = s.indexOf(" as ", idx + 4);
                }
                if (idx != -1) {
                    map.put(s.substring(idx + 4).trim(), s.substring(0, idx).trim());
                } else {
                    int spaceIdx = s.lastIndexOf(" ");
                    if (spaceIdx >= 0) {
                        map.put(s.substring(spaceIdx + 1).trim(), s.substring(0, spaceIdx).trim());
                    } else {
                        map.put(s, s);
                    }
                }
            } else if (s.contains(" ")) {
                // case when a != null then ifnull(a,0) else b end
                if (s.endsWith(" end")) {
                    map.put(s, s);
                    continue;
                } else if (s.contains(" end ")) { // 可能不止一个 end，已经遇到过
                    if (s.contains(")")) {
                        String key = s.substring(s.lastIndexOf(")") + 1).trim();
                        key = key.contains("as ") ? key.split("\\s+")[1] : key;
                        map.put(key, s.substring(0, s.lastIndexOf(")") + 1));
                        continue;
                    } else {
                        int idx = s.lastIndexOf(" end ");
                        map.put(s.substring(idx + 5).trim(), s.substring(0, idx).trim() + " end");
                        continue;
                    }
                }
                if (s.contains("(")) {
                    int leftIdx = s.indexOf("(");
                    Content expectContent = StrUtil.getExpectContent(s, leftIdx);
                    assert expectContent != null;

                    int end = expectContent.getEnd();
                    if (s.length() > end && s.substring(end).trim().length() > 0) {
                        map.put(s.substring(end).trim(), s.substring(0, end).trim());
                    } else {
                        map.put(s, s);
                    }
                    continue;
                }

                // select distinct c.id
                int idx = s.lastIndexOf(" ");
                String[] split = s.split("\\s+");
                if (split.length == 2 && split[0].equalsIgnoreCase("distinct")) {
                    map.put(s, s);
                    continue;
                }
                map.put(s.substring(idx + 1).trim(), s.substring(0, idx).trim());
            } else if (s.contains("(")) {
                int leftIdx = s.indexOf("(");
                Content expectContent = StrUtil.getExpectContent(s, leftIdx);
                assert expectContent != null;
                int end = expectContent.getEnd();
                if (s.length() > end && s.substring(end).trim().length() > 0) {
                    map.put(s.substring(end).trim(), s.substring(0, end).trim());
                } else {
                    map.put(s, s);
                }
            } else {
                s = s.replace("'", "");
                map.put(s, s);
            }
        }
    }
}
//    private static String addParam(StringBuilder sb, List<SQLExpr> parameters) {
//        if (!parameters.isEmpty()) {
//            parameters.forEach(param -> {
//                sb.append(SQLUtils.toMySqlString(param)).append(",");
//            });
//            sb.deleteCharAt(sb.length() - 1);
//        }
//        if (sb.toString().contains("@")) {
//            throw new RuntimeException("有 @ 报错了");
//        }
//        return sb.toString();
//    }
// insert into  单条数据
//    public static Map<String, String> getFunctionValue(String sql) {
//        List<String> keyName2 = getKeyName2(sql);
//        int first = sql.indexOf('(');
//        int second = sql.indexOf('(', first + 1);
//        int end = sql.lastIndexOf(')');
//        String[] valueArr = sql.substring(second + 1, end).split(",");
//        Map<String, String> map = new LinkedHashMap<>();
//        for (int i = 0; i < keyName2.size(); i++) {
//            if (!"?".equals(valueArr[i].trim())) {
//                map.put(keyName2.get(i).trim(), valueArr[i].trim());
//            }
//        }
//        return map;
//    }
//    private static boolean hasCalcSymbol(String s) {
//        return s.contains("+") || s.contains("-") || s.contains("*") || s.contains("/");
//    }
//    private static String processSQLCastExpr(SQLCastExpr param) {
//        SQLExpr expr = param.getExpr();
//        StringBuilder sb = new StringBuilder("cast(");
//
//        addParam(sb, Collections.singletonList(expr));
//
//        sb.append(" as ");
//        SQLDataType dataType = param.getDataType();
//        String name = dataType.getName();
//        List<SQLExpr> arguments = dataType.getArguments();
//        sb.append(name);
//        if (arguments != null && !arguments.isEmpty()) {
//            sb.append("(");
//            addParam(sb, arguments);
//            sb.append(")");
//        }
//        return sb.append(")").toString();
//    }
//            if (sqlExpr instanceof SQLMethodInvokeExpr) {
//                propVal = processSQLMethodInvokeExpr(((SQLMethodInvokeExpr) sqlExpr));
//            } else if (sqlExpr instanceof SQLIdentifierExpr) {
//                propVal = sqlExpr.toString();
//            } else if (sqlExpr instanceof SQLPropertyExpr) {
//                propVal = sqlExpr.toString();
//            } else if (sqlExpr instanceof SQLBinaryOpExpr || sqlExpr instanceof SQLNullExpr) {
//                propVal = sqlExpr.toString();
//            } else if (sqlExpr instanceof SQLIntegerExpr || sqlExpr instanceof SQLCharExpr) {
//                propVal = sqlExpr.toString();
//            } else if (sqlExpr instanceof SQLAggregateExpr) {
//                propVal = processSQLAggregateExpr((SQLAggregateExpr) sqlExpr);
//            } else if (sqlExpr instanceof SQLCaseExpr) {
//                propVal = processSQLCaseExpr((SQLCaseExpr) sqlExpr);
//            } else if (sqlExpr instanceof SQLVariantRefExpr) {
//                propVal = sqlExpr.toString();
//            } else if (sqlExpr instanceof SQLCastExpr) {
//                propVal = processSQLCastExpr((SQLCastExpr) sqlExpr);
//            } else if (sqlExpr instanceof SQLQueryExpr) {
//                propVal = processSQLQueryExpr((SQLQueryExpr) sqlExpr);
//            } else {
//                throw new RuntimeException("Select 报错！！！");
//            }
// 不知道为什么解析器解析出错
//            propVal = propVal.replace("xTRUE", "'TRUE'");
// 有 distinct 的会去掉
//        if (!selectSection.contains("distinct")
//                && !selectSection.contains("case when ") && !selectSection.contains("select ")) {
//            try {
//                Select select = (Select) CCJSqlParserUtil.parse("select " + selectSection);
//                List<SelectItem> selectItems = ((PlainSelect) select.getSelectBody()).getSelectItems();
//                for (SelectItem selectItem : selectItems) {
//                    if (selectItem instanceof SelectExpressionItem) {
//                        String expression = ((SelectExpressionItem) selectItem).getExpression().toString();
//                        Alias alias = ((SelectExpressionItem) selectItem).getAlias();
//                        if (alias != null) {
//                            map.put(alias.getName().trim(), expression.trim());
//                        } else {
//                            map.put(expression.trim(), expression.trim());
//                        }
//                    } else {
//                        map.put(selectItem.toString(), selectItem.toString());
//                    }
//                }
//            } catch (JSQLParserException e) {
//                System.out.println("报错的 SQL ：" + sql);
//                hasErr = true;
//                e.printStackTrace();
////                throw new RuntimeException(e);
//            }
//            if (!hasErr) {
//                return map;
//            } else {
//                map = new HashMap<>();
//            }
//        }
//        try {
//            // group on 报错，其实 group 只是一个别名
//            if (sql.contains(" group on ")) {
//                sql = sql.replaceAll(" group on ", " \"group\" on ");
//            }
//            // 识别 "update xxx;update xxx"
//            Statement statement = CCJSqlParserUtil.parseStatements(sql).getStatements().get(0);
//            if (statement instanceof Insert) {
//                return ((Insert) statement).getTable().getName().trim();
//            } else if (statement instanceof Select) {
//                // SetOperationList 是 Select .. union all Select ...
//                if (((Select) statement).getSelectBody() instanceof SetOperationList) {
//                    List<SelectBody> selects = ((SetOperationList) ((Select) statement).getSelectBody()).getSelects();
//                    return ((PlainSelect) selects.get(0)).getFromItem().toString();
//                }
//                return ((PlainSelect) ((Select) statement).getSelectBody()).getFromItem().toString();
//            } else if (statement instanceof Update) {
//                return ((Update) statement).getTable().getName();
//            } else if (statement instanceof Delete) {
//                return ((Delete) statement).getTable().getName();
//            }
//        } catch (JSQLParserException e) {
//            e.printStackTrace();
//        }
//        return "";
// 获取 group by 的分组字段
//    public static List<String> getGroupByProperties(String sql) {
//        MySqlStatementParser parser = new MySqlStatementParser(sql);
//        SQLSelectStatement sqlSelectStatement = (SQLSelectStatement) parser.parseStatement();
//        SQLSelectQuery query = sqlSelectStatement.getSelect().getQuery();
//        if (query instanceof MySqlSelectQueryBlock) {
//            SQLSelectGroupByClause groupBy = ((MySqlSelectQueryBlock) query).getGroupBy();
//            if (groupBy == null || groupBy.getItems() == null) {
//                SQLTableSource tableSource = ((MySqlSelectQueryBlock) query).getFrom();
//                if (tableSource instanceof SQLSubqueryTableSource) {
//                    SQLSelectGroupByClause groupBy2 = ((MySqlSelectQueryBlock) ((SQLSubqueryTableSource) tableSource).getSelect().getQuery()).getGroupBy();
//                    return groupBy2.getItems().stream().map(Object::toString).collect(Collectors.toList());
//                }
//            } else {
//                List<SQLExpr> items = groupBy.getItems();
//                ArrayList<String> list = new ArrayList<>();
//                if (items.get(0) instanceof MySqlSelectGroupByExpr) {
//                    for (SQLExpr item : items) {
//                        list.add(((MySqlSelectGroupByExpr) item).getExpr().toString());
//                    }
//                    return list;
//                } else {
//                    return groupBy.getItems().stream().map(Object::toString).collect(Collectors.toList());
//                }
//            }
//        } else if (query instanceof MySqlUnionQuery) {
//            MySqlUnionQuery unionQuery = (MySqlUnionQuery) query;
//
//        } else {
//            throw new RuntimeException("未知的类型");
//        }
//        return new ArrayList<>();
//
////        List<String> result = new ArrayList<>();
////        // 面对 select xxx from ((xxx) union (xxx) order by xx) t group by xxx 有问题
////        if (!sql.contains(" union ") && !sql.contains("case when ")) {
////            try {
////                SelectBody selectBody = ((Select) CCJSqlParserUtil.parse(sql)).getSelectBody();
////
////                if (selectBody instanceof PlainSelect) {
////                    processPlainSelect(result, (PlainSelect) selectBody);
////                } else if (selectBody instanceof SetOperationList) {
////                    List<SelectBody> selects = ((SetOperationList) selectBody).getSelects();
////                    for (SelectBody select : selects) {
////                        processPlainSelect(result, (PlainSelect) select);
////                    }
////                }
////            } catch (JSQLParserException e) {
////                System.out.println("报错的SQL：" + sql);
////                throw new RuntimeException(e);
////            }
////            return result;
////        } else {
////            // 兜底方法
////            int idx = sql.indexOf("group by") + "group by".length(), j = idx;
////            boolean hasComma = true;
////            while (j < sql.length() && sql.charAt(j) == ' ') {
////                j++;
////            }
////            while (j < sql.length()) {
////                if (sql.charAt(j) == ' ') {
////                    hasComma = false;
////                    while (j < sql.length() && sql.charAt(j) == ' ') {
////                        j++;
////                    }
////                }
////                if (sql.charAt(j) == ',') {
////                    j++;
////                    while (j < sql.length() && sql.charAt(j) == ' ') {
////                        j++;
////                    }
////                    hasComma = true;
////                }
////                if (sql.charAt(j) != ' ' && sql.charAt(j) != ',' && (!hasComma)) {
////                    break;
////                }
////                j++;
////            }
////            return Arrays.stream(sql.substring(idx, j - 1).split(","))
////                    .map(String::trim).map(it -> it.replaceAll("\\)", ""))
////                    .collect(Collectors.toList());
////        }
//    }

//    private static void processPlainSelect(List<String> result, PlainSelect selectBody) {
//        GroupByElement groupByElement = selectBody.getGroupBy();
//        collectGroupByEle(result, groupByElement);
//        if (selectBody.getFromItem() instanceof SubSelect) {
//            SelectBody subSelect = ((SubSelect) selectBody.getFromItem()).getSelectBody();
//            if (subSelect instanceof PlainSelect) {
//                collectGroupByEle(result, ((PlainSelect) subSelect).getGroupBy());
//            } else if (subSelect instanceof SetOperationList) {
//                List<SelectBody> selects = ((SetOperationList) subSelect).getSelects();
//                for (SelectBody select : selects) {
//                    collectGroupByEle(result, ((PlainSelect) select).getGroupBy());
//                }
//            }
//        }
//    }

//    private static void collectGroupByEle(List<String> result, GroupByElement groupByElement) {
//        if (groupByElement != null) {
//            List<Expression> expressions = groupByElement.getGroupByExpressionList().getExpressions();
//            for (Expression expression : expressions) {
//                result.add(expression.toString());
//            }
//        }
//    }
//                if (param instanceof SQLMethodInvokeExpr) {
//                    sb.append(processSQLMethodInvokeExpr(((SQLMethodInvokeExpr) param)));
//                } else if (param instanceof SQLAggregateExpr) {
//                    sb.append(processSQLAggregateExpr(((SQLAggregateExpr) param)));
//                } else if (param instanceof SQLCaseExpr) {
//                    sb.append(processSQLCaseExpr((SQLCaseExpr) param));
//                } else if (param instanceof SQLInListExpr) {
//                    sb.append(processSQLInListExpr((SQLInListExpr) param));
//                } else if (param instanceof SQLUnaryExpr) {
//                    SQLExpr expr = ((SQLUnaryExpr) param).getExpr();
//                    if (expr instanceof SQLBinaryOpExpr) {
//                        sb.append(processOperator(((SQLBinaryOpExpr) expr).getOperator())).append(processSQLBinaryOpExpr((SQLBinaryOpExpr) expr));
//                    } else {
//                        throw new RuntimeException("SQLUnaryExpr 出错了");
//                    }
//                } else if (param instanceof SQLAllColumnExpr) {
//                    sb.append(" * ");
//                } else if (param instanceof SQLQueryExpr) {
//
//                    sb.append(processSQLQueryExpr((SQLQueryExpr) param));
//                } else if (param instanceof MySqlSelectGroupByExpr) {
//                    sb.append(processSQLGroupBy((MySqlSelectGroupByExpr) param));
//                } else if (param instanceof SQLNullExpr) {
//                    sb.append("NULL");
//                } else if (param instanceof SQLCharExpr) {
//                    String text = ((SQLCharExpr) param).getText();
//                    sb.append(text != null && text.length() > 0 ? "'" + text + "'" : "''");
//                } else if (param instanceof SQLBinaryOpExpr) { // @a := date_format(@a,'%Y')
//                    sb.append(processSQLBinaryOpExpr((SQLBinaryOpExpr) param));
//                } else if (param instanceof MySqlIntervalExpr) {
//                    sb.append("interval ").append(param.toString());
//                } else {
//                    sb.append(param.toString());
//                }
//    private static String processSQLGroupBy(MySqlSelectGroupByExpr param) {
//        SQLExpr expr = param.getExpr();
//        StringBuilder sb = new StringBuilder();
//        addParam(sb, Collections.singletonList(expr));
////      达梦不支持 group by 的字段排序
//        return sb.append(" ").toString();
//    }

//    public static String processSQLQueryExpr(SQLQueryExpr param) {
//        SQLSelect subQuery = param.getSubQuery();
//        MySqlSelectQueryBlock query = (MySqlSelectQueryBlock) subQuery.getQuery();
//        List<SQLSelectItem> selectList = query.getSelectList();
//        SQLTableSource tableSource = query.getFrom();
//        SQLExpr where = query.getWhere();
//        MySqlSelectQueryBlock.Limit limit = query.getLimit();
//        StringBuilder subSelectSb = new StringBuilder("(select ");
//        HashMap<String, String> selectItemMap = new HashMap<>();
//        processSelectItem(selectItemMap, selectList);
//        for (Map.Entry<String, String> entry : selectItemMap.entrySet()) {
//            if (!entry.getKey().equals(entry.getValue())) {
//                subSelectSb.append(entry.getValue()).append(" ").append(entry.getKey());
//            } else {
//                subSelectSb.append(entry.getValue());
//            }
//
//        }
//        if (tableSource != null) {
//            subSelectSb.append(" from ");
//            subSelectSb.append(getTableNameAndAlias(tableSource));
//        }
//
//        if (where != null) {
//            subSelectSb.append(" where ");
//            addParam(subSelectSb, Collections.singletonList(where));
//        }
//        String orderBy = processOrderBy(query.getOrderBy());
//        String groupBy = processGroupBy(query.getGroupBy());
//        String limitSql = processLimit(limit);
//        subSelectSb.append(groupBy);
//        subSelectSb.append(orderBy);
//        subSelectSb.append(limitSql);
//        subSelectSb.append(") ");
//        return subSelectSb.toString();
//    }

//    private static String processLimit(MySqlSelectQueryBlock.Limit limit) {
//        if (limit != null) {
//            SQLExpr offset = limit.getOffset();
//            SQLExpr rowCount = limit.getRowCount();
//            StringBuilder sb = new StringBuilder();
//            sb.append(" limit ");
//            if (offset != null) {
//                addParam(sb, Collections.singletonList(offset));
//                sb.append(",");
//            }
//            if (rowCount != null) {
//                addParam(sb, Collections.singletonList(rowCount));
//            }
//            return sb.append(" ").toString();
//        }
//        return " ";
//    }

//    private static String processOrderBy(SQLOrderBy orderBy) {
//        if (orderBy != null) {
//            List<SQLSelectOrderByItem> items = orderBy.getItems();
//            StringBuilder sb = new StringBuilder(" order by ");
//
//            for (SQLSelectOrderByItem item : items) {
//                SQLExpr expr = item.getExpr();
//                addParam(sb, Collections.singletonList(expr));
//                if (item.getType() != null) {
//                    sb.append(item.getType().name()).append(",");
//                }
//            }
//            return sb.deleteCharAt(sb.length() - 1).append(" ").toString();
//        } else {
//            return " ";
//        }
//    }

//    private static String processGroupBy(SQLSelectGroupByClause groupBy) {
//        if (groupBy != null) {
//            List<SQLExpr> items = groupBy.getItems();
//            SQLExpr having = groupBy.getHaving();
//            StringBuilder sb = new StringBuilder();
//            sb.append(" group by ");
//            addParam(sb, items);
//            if (having != null) {
//                sb.append(" having ");
//                addParam(sb, Collections.singletonList(having));
//            }
//            return sb.append(" ").toString();
//        } else {
//            return " ";
//        }
//    }

//    private static String getTableNameAndAlias(SQLTableSource tableSource) {
//        if (tableSource == null) {
//            return " ";
//        }
//        StringBuilder sb = new StringBuilder();
//        if (tableSource instanceof SQLExprTableSource) {
//            SQLExpr expr = ((SQLExprTableSource) tableSource).getExpr();
//
//            addParam(sb, Collections.singletonList(expr));
//        }
//        String alias = tableSource.getAlias();
//        if (alias != null) {
//            sb.append(" ").append(alias);
//        }
//        return sb.append(" ").toString();
//    }

//    private static String processSQLInListExpr(SQLInListExpr param) {
//        boolean isNot = param.isNot();
//        StringBuilder sb = new StringBuilder();
//        SQLExpr expr = param.getExpr();
//        List<SQLExpr> targetList = param.getTargetList();
//        addParam(sb, Collections.singletonList(expr));
//        if (isNot) {
//            sb.append(" not ");
//        }
//        sb.append(" in ").append("(");
//        addParam(sb, targetList);
//        sb.append(")");
//        return sb.toString();
//    }

//    private static String processSQLBinaryOpExpr(SQLBinaryOpExpr expr) {
//        return expr.toString();
//    }

//    private static String processOperator(SQLBinaryOperator operator) {
//        return operator.getName();
//    }

//    private static String processSQLMethodInvokeExpr(SQLMethodInvokeExpr param) {
//        String methodName = param.getMethodName();
//        StringBuilder sb = new StringBuilder("(");
//        addParam(sb, param.getParameters());
//        return methodName + sb.append(")");
//    }

//    private static String processSQLCaseExpr(SQLCaseExpr param) {
//        List<SQLCaseExpr.Item> items = param.getItems();
//        StringBuilder sb = new StringBuilder();
//        boolean isFirst = true;
//        for (SQLCaseExpr.Item item : items) {
//            if (isFirst) {
//                sb.append(" case when ");
//                isFirst = false;
//            } else {
//                sb.append(" when ");
//            }
//            addParam(sb, Collections.singletonList(item.getConditionExpr()));
//            sb.append(" then ");
//            addParam(sb, Collections.singletonList(item.getValueExpr()));
////            sb.append(item.getConditionExpr()).append(" then ").append(item.getValueExpr());
//        }
//        return sb.append(" end ").toString();
//    }

//    private static String processSQLAggregateExpr(SQLAggregateExpr param) {
//        String methodName = param.getMethodName();
//        StringBuilder sb = new StringBuilder("(");
//        // 比如 distinct
//        if (param.getOption() != null) {
//            sb.append(param.getOption()).append(" ");
//        }
//        addParam(sb, param.getArguments());
//        return methodName + sb.append(")");
//    }